use x86_64::VirtAddr;

#[derive(Debug, Clone, Copy, Default)]
#[repr(packed)]
pub struct SysContext {
    pub r15: usize,
    pub r14: usize,
    pub r13: usize,

    pub r12: usize,
    pub r11: usize,
    pub r10: usize,
    pub r9: usize,

    pub r8: usize,
    pub rbp: usize,
    pub rsi: usize,
    pub rdi: usize,

    pub rdx: usize,
    pub rcx: usize,
    pub rbx: usize,
    pub rax: usize,
}

impl SysContext {
    #[inline]
    pub fn address(&self) -> VirtAddr {
        VirtAddr::new(self as *const SysContext as u64)
    }

    #[inline]
    pub fn from_address(address: VirtAddr) -> SysContext {
        unsafe { *&mut *(address.as_u64() as *mut SysContext) }
    }

    #[inline]
    pub fn get_syscall_num(&self) -> usize {
        self.rax
    }

    #[inline]
    pub fn get_syscall_args(&self) -> (usize, usize, usize, usize, usize, usize) {
        (self.rdi, self.rsi, self.rdx, self.r10, self.r8, self.r9)
    }

    #[inline]
    pub fn set_syscall_ret(&mut self, ret: usize) {
        self.rax = ret;
    }
}

#[macro_export]
macro_rules! push_sys_context {
    () => {
        concat!(
            r#"
            push rax
            push rbx
            push rcx
            push rdx
            push rdi
            push rsi
            push rbp
            push r8
            push r9
            push r10
            push r11
            push r12
            push r13
            push r14
            push r15
            "#,
        )
    };
}

#[macro_export]
macro_rules! pop_sys_context {
    () => {
        concat!(
            r#"
            pop r15
            pop r14
            pop r13
            pop r12
            pop r11
            pop r10
            pop r9
            pop r8
            pop rbp
            pop rsi
            pop rdi
            pop rdx
            pop rcx
            pop rbx
            pop rax
			"#
        )
    };
}
